#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hs/hs.h>

#define MAX_ITEMS 10

// 正则表达式ID号枚举类型
enum
{
    HYPERSCAN_ID_TEST0 = 0,
    HYPERSCAN_ID_TEST1,
    HYPERSCAN_ID_TEST2,
    HYPERSCAN_ID_MAX
};

// 单个正则表达式数据结构
typedef struct
{
    unsigned int id;
    const char *str;
} expr_t;

// 多模正则表达式信息数据结构
typedef struct
{
    int ids[MAX_ITEMS];
    int flags[MAX_ITEMS];
    const char *exprs[MAX_ITEMS];
} expr_array_t;

// 正则表达式数组(全局变量)
static const expr_t gPattern[] = {
        {HYPERSCAN_ID_TEST0, "ab+"},
        {HYPERSCAN_ID_TEST1, "cd{2,}"},
        {HYPERSCAN_ID_TEST2, "ef{1,3}"},
        {HYPERSCAN_ID_MAX, NULL}
};

// 函数原型
// 编译正则表达式
hs_database_t* do_compile(const char **expr, int *flags, int *ids, int cnt);
// 申请临时空间
hs_scratch_t* get_scratch(const hs_database_t *hs_db);
// 多模+块匹配
int do_scan(const char *input, int input_len, const hs_database_t *hs_db,
            hs_scratch_t* hs_scratch);

// 定义一个回调函数，当匹配时被调用
static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx);

int main(int argc, char **argv)
{
    int i = 0;
    expr_array_t rs;

    // 将正则表达式数组一对一转存到结构体数据结构
    for(i = 0; gPattern[i].str; i++)
    {
        rs.ids[i] = gPattern[i].id;
        rs.exprs[i] = gPattern[i].str;
        rs.flags[i] = HS_FLAG_SOM_LEFTMOST | HS_FLAG_CASELESS;
    }

    // 编译正则表达式
    hs_database_t *database = do_compile(rs.exprs, rs.flags, rs.ids, i);
    if(database == NULL)
    {
        return -1;
    }

    hs_scratch_t* scratch = get_scratch(database);
    if(scratch == NULL)
    {
        hs_free_database(database);
        return -1;
    }

    // 单模+块扫描
    const char *input[] ={"abbcddefdefffabefffff",
                          "abc123123123abcmax123123bacbacabc",
                          NULL};

    for(i = 0; input[i]; i++)
    {
        do_scan(input[i], strlen(input[i]), database, scratch);
    }

    // 释放空间
    hs_free_scratch(scratch);
    hs_free_database(database);

    return 0;
}

// 编译正则表达式
hs_database_t* do_compile(const char **expr, int *flags, int *ids, int cnt)
{
    hs_database_t *hs_db = NULL;
    hs_compile_error_t *compile_err = NULL;
    hs_error_t hs_error = 0;

    // 多模+块扫描
    hs_error = hs_compile_multi(expr, (const unsigned int *)flags,
                                (const unsigned int *)ids, cnt,
                                HS_MODE_BLOCK, NULL, &hs_db, &compile_err);
    if (hs_error)
    {
        printf("hs_compile_multi ERR_CODE[%d]: Pattern[%u]:\"%s\""
                " with error:\"%s\"",
                hs_error,
                ids[compile_err->expression],
                expr[compile_err->expression],
                compile_err->message);
        hs_free_compile_error(compile_err);
        return NULL;
    }

    return hs_db;
}

// 申请临时空间
hs_scratch_t* get_scratch(const hs_database_t *hs_db)
{
    hs_error_t hs_error = 0;
    hs_scratch_t *hs_scratch = NULL; // 必须初始化为NULL
    hs_error = hs_alloc_scratch(hs_db, &hs_scratch);
    if (hs_error)
    {
        printf("hs_alloc_scratch ERR_CODE[%d]\n", hs_error);
        return NULL;
    }

    return hs_scratch;
}

// 多模+块匹配
int do_scan(const char *input, int input_len, const hs_database_t *hs_db,
            hs_scratch_t* hs_scratch)
{
    printf("do_scan %s\n", input);
    hs_error_t hs_err = 0;
    hs_err = hs_scan(hs_db, input, input_len, 0, hs_scratch,
                     on_match, (void*)input);
    if (hs_err)
    {
        printf("ERR_CODE[%d] hs_scan\n", hs_err);
        return -1;
    }

    return 0;
}

// 定义一个回调函数，当匹配时被调用
static int on_match(unsigned int id, unsigned long long from,
        unsigned long long to, unsigned int flags, void *ctx)
{
    char *tmp = (char*)ctx;

    size_t len = to - from;

    printf("Matched ID: %d, Matched pattern: %s\n", id, gPattern[id].str);

    printf("Matched sub-string from %lld to %lld: %.*s\n", from, to,
                                                    (int)len, tmp + from);

    return 0;
}
